/*
 * Copyright (C) 2007 Evan Long    longx223 (at) umn (dot) edu
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/**
 * @file   vlc_control.c
 * @author Evan Long
 * 
 * @brief  Implementation to control a vlc_control_t instance.
 * 
 * 
 */

#include <stdio.h>
#include <string.h>
#include <vlc/vlc.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "vlc_control.h"
#include "safe_malloc.h"
#include "monitor_loop.h"
#include "gesture_recognition.h"
#include "image_proc.h"
#include "cvector.h"
#include "framegrabber.h"
#include "util.h"

static char* stringcmds[] = {"play", "pause", "stop", "faster", "slower", 
			     "volume up", "volume down", 0};

vlc_control_t* new_vlc_control(int argc, char** argv)
{
  vlc_control_t* tmp = (vlc_control_t*)safe_malloc(sizeof(vlc_control_t));

  /*figure out which mode we should be in*/
  char mode = *argv[argc-1];
  argv[argc-1] = 0;
  argc--;

  if((tmp->vlcid = VLC_Create()) < 0)
  {
    printf("%s\n", VLC_Error(tmp->vlcid));
    exit(1);
  }

  VLC_CALL(VLC_Init(tmp->vlcid, argc, argv));
  VLC_CALL(VLC_AddIntf(tmp->vlcid, "wxwidgets", 0, 0));

  tmp->cmd[PLAY].fcall = vlc_play_wrap;
  tmp->cmd[PAUSE].fcall = vlc_pause_wrap;
  tmp->cmd[STOP].fcall = vlc_stop_wrap;
  tmp->cmd[FF].fcall = vlc_ff_wrap;
  tmp->cmd[RR].fcall = vlc_rr_wrap;
  tmp->cmd[VUP].fcall = vlc_vup_wrap;
  tmp->cmd[VDOWN].fcall = vlc_vdown_wrap;

  if(mode == PROGRAM)
  {
    /*have user enter in commands*/
    frame_grabber_t* frame = new_frame_grabber("/dev/video");
    int i=0;
    while(i < NCOMMANDS)
    {
      printf("Enter in the %s command\n", stringcmds[i]);
      monitor_state_t state = MONITOR;
      cvector_t* points;
      char* cmd;

      while(state != EXIT)
      {
	point_t p = find_brightest_point(grab_frame(frame), frame->width, 
					 frame->height);
	if(p.x == -1)
	{
	  if(state == RECORD)
	  {
	    state = EXIT;
	    cmd = detect_gesture(points);
	    free_vector(points);
	  }
	}
	else
	{
	  if(state == MONITOR)
	  {
	    state = RECORD;
	    points = new_cvector(sizeof(point_t));
	  }
	  add_element(points, &p);
	}
      }
      
      printf("Is this the correct gesture %s?\n", cmd);
      char yesno[3];
      fgets(yesno, 3, stdin);
      if(yesno[0] == 'y')
      {
	strcpy(tmp->cmd[i].cmdstr, cmd);
	i++;
      }

      free(cmd);
    }
    free_frame_grabber(frame);
    printf("Laser gestures have been programmed.\n");
    printf("Would you like to save them to vlclasergesturecontrol.cfg?\n");
    char yesno[3];
    fgets(yesno, 3, stdin);
    if(yesno[0] == 'y')
    {
      save_vlc_command(tmp);
    }
  }
  else if(mode == LOAD)
  {
    xmlDoc *doc = xmlReadFile("config.xml", NULL, 0);
    if(doc == NULL)
    {
      fprintf(stderr, "Opening configuration file failed.");
      set_vlc_defaults(tmp);
      return tmp;
    }

    xmlNode *root = xmlDocGetRootElement(doc);
    xmlNode *node = NULL;
    char* gesture = NULL;
    char* command = NULL;
    if(root && strcmp((char*)root->name, "gestures") == 0)
    {
      for(node = root->children; node; node = node->next)
      {
	if(node->type == XML_ELEMENT_NODE && 
	   strcmp((char*)node->name, "gesture") == 0) 
	{
	  gesture = (char*)node->children->content;
	  xmlAttr *attr = node->properties;
	  if(attr)
	  {
	    command = (char*)attr->children->content;
	    if(command)
	    {
	      set_vlc_command(tmp, command, gesture);
	    }
	  }
	}
      }
    }
    
    xmlCleanupParser();
  }
  else if(mode == DEFAULTS)
  {
    set_vlc_defaults(tmp);
  }

  return tmp;
}

void set_vlc_defaults(vlc_control_t* con)
{
  strcpy(con->cmd[PLAY].cmdstr, "3r1l");
  strcpy(con->cmd[PAUSE].cmdstr, "2r0d");
  strcpy(con->cmd[STOP].cmdstr, "0u2l");
  strcpy(con->cmd[FF].cmdstr, "1r3r");
  strcpy(con->cmd[RR].cmdstr, "3r1r");
  strcpy(con->cmd[VUP].cmdstr, "0u99");
  strcpy(con->cmd[VDOWN].cmdstr, "0d99");
}


void set_vlc_command(vlc_control_t* con, 
		     const char* command, 
		     const char* gesture)
{
  int count = 0;
  while(stringcmds[count])
  {
    if(strcmp(stringcmds[count], command) == 0)
    {
      strncpy(con->cmd[count].cmdstr, gesture, 4);
    }
    count++;
  }
}

void exec_vlc_command(vlc_control_t* con, char *cmd)
{
  int i;
  for(i=0; i<NCOMMANDS; i++)
  {
    if(strcmp(con->cmd[i].cmdstr, cmd) == 0)
    {
      con->cmd[i].fcall(con->vlcid);
      return;
    }
  }
}

void save_vlc_command(vlc_control_t* con)
{
  FILE* cfg = fopen("vlclasergesturecontrol.cfg", "w");
  int i;
  for(i=0; i<NCOMMANDS; i++)
  {
    fprintf(cfg, "%s\n", con->cmd[i].cmdstr);
  }
  fclose(cfg);
}

void vlc_play_wrap(int vlcid)
{
  VLC_CALL(VLC_Play(vlcid));
}

void vlc_pause_wrap(int vlcid)
{
  VLC_CALL(VLC_Pause(vlcid));
}

void vlc_stop_wrap(int vlcid)
{
  VLC_CALL(VLC_Stop(vlcid));
}

void vlc_ff_wrap(int vlcid)
{
  VLC_CALL(VLC_SpeedFaster(vlcid));
}

void vlc_rr_wrap(int vlcid)
{
  VLC_CALL(VLC_SpeedSlower(vlcid));
}

void vlc_vup_wrap(int vlcid)
{
  int curr = VLC_VolumeGet(vlcid);
  curr = (curr+10 > 200) ? 200 : curr+10;
  VLC_VolumeSet(vlcid, curr);
}

void vlc_vdown_wrap(int vlcid)
{
  int curr = VLC_VolumeGet(vlcid);
  curr = (curr-10 < 0) ? 0 : curr-10;
  VLC_VolumeSet(vlcid, curr);
}
